﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;

namespace mates_viz
{
  
    class UILocation
    {
        UIVizualization parentViz; public UIVizualization ParentViz { get { return parentViz; } }

        private int loc_id; public int Loc_ID { get { return loc_id; } }
        private double distance; public double Distance { get { return distance; } }
        LinkedList<UIArc> Arcs = new LinkedList<UIArc>();

		int colorIndex; public int ColorIndex { get { return colorIndex; } }
		public Color Color { get { return UIVizualization.vizPalette[colorIndex]; } }
		SolidColorBrush colorBrush; 
		public SolidColorBrush ColorBrush { 
			get {
				// get a new color if one hasn't already been defined yet
				if (Arcs.Count == 0)
				{
					colorIndex = parentViz.findSafeColor(this);
					colorBrush = new SolidColorBrush(UIVizualization.vizPalette[colorIndex]);
					parentViz.AddLocationToKey(this);	// show/update this location in the key
				}
				return colorBrush; 
			} 
		}
	
		public void UpdateBrightness(double newValue)
		{
			// search through my arcs, change all their brightnesses
			LinkedListNode<UIArc> arc = Arcs.First;
			while (arc != null)
			{
				arc.Value.SetBrightness(newValue);
				arc = arc.Next;
			}
		}

        public UILocation(UIVizualization ParentViz, int Loc_ID)
        {
            loc_id = Loc_ID;
            parentViz = ParentViz;
            // Color for the location will be selected when it is actually drawn.			
            distance = parentViz.StateManager.GetLocation(loc_id).Distance;
        }

        // return the first arc in the linkedlist, or null if there are no arcs yet.
        public UIArc FirstArc { get { if (Arcs.Count == 0) return null; else return Arcs.First.Value; } }

        // return the first arc in the linkedlist, or null if there are no arcs yet.
        public UIArc LastArc { get { if (Arcs.Count == 0) return null; else return Arcs.Last.Value; } }

        public void RemoveArc(UIArc toRemove)
        {
            try {
                Arcs.Remove(toRemove);
                if (Arcs.Count == 0) parentViz.RemoveLoc(this); // if this was my last arc, eliminate me.
            }
            catch { Error.Log(" UILoc: I could not find the arc I was asked to remove from the list!"); }
        }

        public void RemoveArcFromCanvas(UIArc toRemove)
        {
            Error.Log("UILoc: Removing arc on ring " + toRemove.RingIndex.ToString() +
                " which starts at " + toRemove.StartTick.ToString() + " and ends at " + toRemove.EndTick.ToString());
            try { parentViz.RemoveFromCanvas(toRemove.arcCanvas);
        }
            catch { Error.Log(" UILoc: I could not find the arc canvas I was asked to remove from the viz!");}
        }

        /// <summary>
        /// This function searches for the next arc (starting from curArc) in the visualization. 
        /// If there aren't any in this loc, it gets the first arc from the next location.
        /// </summary>
        /// <param name="curArc">The current arc from which to start the search.</param>
        /// <returns></returns>
        public UIArc NextArc(UIArc curArc)
        {
            UIArc nextArc = NextArcInLoc(curArc);   // check if there's another arc in this loc
            if(nextArc == null)     // if not, look for the next loc, and find it's first arc.
            {
                UILocation nextLoc = parentViz.NextLoc(this);    // find the next location
                if (nextLoc != null)
                    return nextLoc.FirstArc;     // grab the first arc of the next loc
                else 
                    return null;                 // no parent locs --> no next arc
            }
            else
               return nextArc;       // otherwise return the next arc in this loc.
        }
        public UIArc NextArcInLoc(UIArc curArc)
        {
            LinkedListNode<UIArc> curArcNode = Arcs.Find(curArc);
            if (curArcNode.Next == null) return null;   // no more arcs in this loc --> null         
            else return curArcNode.Next.Value;          // otherwise return the next arc in this loc.
        }

		public void HighlightSelf(bool on)
		{
			// go through my arcs, highlight each one
			LinkedListNode<UIArc> arc = Arcs.First;
			while (arc != null)
			{
				arc.Value.HighlightSelf(on);
				arc = arc.Next;
			}
		}

        public void HighlightUser(string username, bool on, string highlight_type)
        {
            // search through my arcs, and find the user.
            // once we find the user, higlight it.
            LinkedListNode<UIArc> arc = Arcs.First;
            while (arc != null)
            {
                // attempt to locate and highlight the user.  if found, return now.
                if (arc.Value.HighlightUser(username, on, highlight_type) == true) return;
                arc = arc.Next;
            }
        }

        public void AddUser(string username)
        {

            // if there are no arcs yet, create the first one.
            if (Arcs.Count == 0)  {

				UIVizualization.VizAddr insertionPoint;
				// determine where this location will be inserted into the viz
				insertionPoint = parentViz.FindInsertionPoint(this);
				int startTick = insertionPoint.tickIndex;  // starting position of the arc.
                int startRing = insertionPoint.ringIndex;  // starting ring for the arc.
				                
                UIArc newArc = new UIArc(this, startTick, startRing);
                Arcs.AddFirst(new LinkedListNode<UIArc>(newArc));
                parentViz.AddToCanvas(newArc.arcCanvas);
            }

            // if we filled up the outermost arc, create a new one on the next ring
            if (Arcs.Last.Value.FillsRing) 
                AddNewArc();    // add a new arc to the outermost ring
            
            Arcs.Last.Value.AddUser(username);  // finally, add the user to the last arc.
        }

        /// <summary>
        /// Adds a new arc to the next outermost ring.
        /// </summary>
        /// <returns>The newly created arc.</returns>
        public UIArc AddNewArc()
        {
            UIArc newArc = new UIArc(this, 0, Arcs.Last.Value.RingIndex + 1);
            Arcs.AddLast(new LinkedListNode<UIArc>(newArc));
            parentViz.AddToCanvas(newArc.arcCanvas);
            return newArc;
 
        }         

        public void RemoveUser(string username)
        {
            // search through my arcs, and find the user.
            // once we find the user, remove it.
            LinkedListNode<UIArc> arc = Arcs.First;
            while (arc != null)
            {
                // attempt to locate and remove the user.  if found, return now.
                if (arc.Value.RemoveUser(username) == true) return;
                arc = arc.Next;
            }
        }

    }
}
